import pygame
from pygame.locals import *
from math import floor
import random
#import psyco
import sane as psyco
#psyco.bind(random.Random.normalvariate)

# attitudes
A_FRIENDLY = 0
A_NEUTRAL = 1
A_HOSTILE = 2

# special group ID
G_PARTY = 0

# Role codes
R_PEASANT = 0
R_ROGUE = 1
R_PRIEST = 2
R_WARRIOR = 3
R_MAGE = 4
R_CRUSADER = 5
R_UNDEAD_SLAYER = 6
R_TRICKSTER = 7
R_WARLOCK = 8

# Role code texts
role_texts = {}
role_texts[R_PEASANT]="Peasant"
role_texts[R_ROGUE]="Rogue"
role_texts[R_PRIEST]="Priest"
role_texts[R_WARRIOR]="Warrior"
role_texts[R_MAGE]="Mage"
role_texts[R_CRUSADER]="Crusader"
role_texts[R_UNDEAD_SLAYER]="Undead Slayer"
role_texts[R_TRICKSTER]="Trickster"
role_texts[R_WARLOCK]="Warlock"

# define object codes
O_G_WARRIOR = 001
O_G_MAGE = 002
O_G_ROGUE = 003
O_G_PRIEST = 004
O_G_UNDEAD_SLAYER = 005
O_G_WARLOCK = 006
O_G_CRUSADER = 8
O_G_TRICKSTER = 007
O_SWORD = 100
O_AXE = 101
O_SPEAR = 102
O_STAFF = 103
O_MACE = 104
O_SHORTSWORD = 105
O_WARLOCK_SWORD = 106
O_GREAT_AXE = 107
O_FLAIL = 108
O_TROLLISH_SHORTSWORD = 109
O_HOLY_SWORD = 110
O_STAFF_OF_HEALING = 111
O_STAFF_UNDEAD_TURNING = 112
O_POISONED_DAGGER = 113
O_DRAGON_SLAYER = 114
O_BOW = 200
O_ELVEN_BOW = 201
O_FIRE_BOW = 202
O_CROSSBOW = 203
O_SPEED_BOW = 204
O_WAND = 250
O_FIRE_WAND = 251
O_LIGHTNING_WAND = 252
O_DIVINER_WAND = 253
O_SPEED_BOOTS = 300
O_SHOES = 301
O_BOOTS = 302
O_ELVEN_BOOTS = 303
O_SPEED_BOOTS = 304
O_JUMPING_BOOTS = 305
O_WATER_WALKING_BOOTS = 306
O_COPPER = 400
O_SILVER = 401
O_GOLD = 402
O_GEMS = 403
O_SMALL_FOOD = 410
O_BIG_FOOD = 411
O_HEALING_POT = 390
O_MAGIC_POT = 391
O_FIRERES_POT = 392
O_STONESKIN_POT = 393
O_CHAMELEON_POT = 394
O_BLINK_POT = 395
O_ANTIDOTE_POT = 396
O_CHEST_SMALL = 397
O_ORB_LIFE = 398
O_GAUNTLETS_OF_POWER = 399
O_AMULET_FIRERES = 320
O_AMULET_PROTECTION = 321
O_AMULET_MAGICRES = 322
O_AMULET_MISSILERES = 323
O_RING_COMBAT = 330
O_RING_KNOWLEDGE = 331
O_RING_MAGIC = 332
O_KEY_GOLD = 500
O_KEY_SILVER = 501
O_KEY_RED = 502
O_KEY_BLUE = 503
O_KEY_GREEN = 504
O_YOU_SKELETON = 600

# define slots
SL_GARB = 0
SL_MELEE = 10
SL_MISSILE = 20
SL_BOOTS = 30 # everything from here down is in an inventory slot
SL_GLOVES = 31
SL_AMULET = 32
SL_RING = 33
SL_KEY = 38
SL_MISC_ITEM = 39
SL_MONEY = 40
SL_FOOD = 41
SL_POTION = 42
# Don't add slots for stuff you can carry more than one of!

# Condition type codes      
C_DEAD = 0          # Monster or PC
C_UNCONSCIOUS = 1   # PC only
C_ESCAPED = 2       # Either
C_ASLEEP = 3
C_PARALYSED = 4
C_CHARMED = 5    # monster charmed by the PC
C_PANICKED = 6
C_DEFENDING = 7
C_CONFUSED = 8    # Either
C_CIRCLE_OF_PROTECTION = 9
C_SNEAKING = 10
C_DODGING = 11
C_STONESKIN = 12
C_CHAMELEON = 13
C_FIRERES_FROM_SPELL = 14
C_FIRERES_FROM_POTION = 15
C_BLESSED = 16
C_AFRAID = 17  
C_POISONED = 18
C_INVISIBLE = 19 # monster only at this stage - if applied to PC, would not give any stealth, defense, or avoiding monster benefits

# Monster codes
M_SHAMBLER = 1 
M_GOBLIN = 2 
M_SKELETON = 3
M_BAT = 4 
M_HARPY = 5 
M_LEPRECHAUN = 6 
M_FIRE_LIZARD = 7 
M_GOBLIN_ARCHER = 8 
M_BRIGAND = 9
M_INVISIBLE_STALKER = 10 
M_OGRE = 11 
M_APPRENTICE = 12 
M_SORCERER = 13 
M_DARK_ELF = 14 
M_SALAMANDER = 15 
M_GOBLIN_SHAMAN = 16 
M_ORC = 17 
M_SPIDER = 18
M_STATUE = 19 
M_WRAITH = 20 
M_WIGHT = 21 
M_FIREDRAKE = 22 
M_CHAMELEON = 23 
M_SNAKE = 24
M_ORC_CAPTAIN = 25
M_SEA_SERPENT = 26
M_CHARACTER = 27

# Move codes - what happens when you try to move into a space?
M_FAIL = 0
M_EASY = 1
M_HIT = 2
M_PUSH = 3

# Direction codes
DIR_UP = 8
DIR_NE = 9
DIR_RIGHT = 6
DIR_SE = 3
DIR_DOWN = 2
DIR_SW = 1
DIR_LEFT = 4
DIR_NW = 7
DIR_HERE = 5
DIRS_AROUND = [7,8,9,6,3,2,1,4]

# Size codes
SZ_SMALL = 1
SZ_MEDIUM = 2
SZ_LARGE = 3

# Tile types
T_WALL = 0
T_STATUE_WALL = 1
T_BOOKCASE = 2
T_DESK = 3
T_RUBBLE = 4
T_DARK_ALTAR = 5
T_TABLE = 6
T_STATUE = 7
T_WATER_WALL = 8
T_FLOOR = 10
T_THRONE = 11
T_STOOL = 12
T_GRAVESTONE = 13
T_GRAVEYARD = 14
T_GRAVEMARKER = 15
T_FLOOR_NOTELEPORT = 16
T_DOOR = 20
T_LOCKED_DOOR_GOLD = 21
T_LOCKED_DOOR_SILVER = 22
T_LOCKED_DOOR_RED = 23
T_LOCKED_DOOR_GREEN = 24
T_LOCKED_DOOR_BLUE = 25
T_EXIT = 30
T_HOLE = 31
T_ENTRANCE = 32
T_STAIRS_UP = 40
T_STAIRS_DOWN = 41
T_FIRE_PIT = 50
T_CAMPFIRE = 51
T_PIT = 52
T_WATER = 60
T_WEB = 70
T_FOUNTAIN = 80
T_SIGNPOST = 90
T_GATE = 100
T_LOCKED_GATE_GOLD = 101
T_LOCKED_GATE_SILVER = 102
T_LOCKED_GATE_RED = 103
T_LOCKED_GATE_GREEN = 104
T_LOCKED_GATE_BLUE = 105
T_RUNE_TELEPORT = 110
T_RUNE_CONFUSION = 111
T_RUNE_PAIN = 112
T_LETTER = 120

# Wall looks 
W_BIGSTONE = 0 # looks good with F_COBBLES. OKish with F_ORDINARY, F_EARTH
W_BIGSTONE_DARK = 1 # shaded version of same
W_WHITE = 2 # with F_ORDINARY, or possibly F_COBBLES
W_WOOD = 3 # with F_EARTH
W_LAST = 4 # keep this updated
W_ORDINARY = -1 # doesn't look so great. Could try putting a black box around it...?

# Floor looks
F_ORDINARY = 0 
F_EARTH = 1
F_COBBLES = 2 # same as W_ORDINARY
F_COBBLES_DARK = 3 # darker version of same
F_OTHER_COBBLES = 4 # from Marten Woxburg
F_FLECKS = 5 # ditto
F_WITH_MAGMA = 6
F_ORDINARY_DARK = 7
F_LAST = 8 # keep this updated      
F_ROCK = -1
F_MOSSY = -2

# Encounter themes
E_OTHER = 0 # if a theme is not assigned a prob mult, it gets the prob mult of this
E_GOBLIN = 1
E_HUMANOID = 2
E_ORC = 3
E_DISGUISED = 4
E_UNDEAD = 5
E_CREEPY_CRAWLY = 6
E_UNDEFENDED_TREASURE = 7
E_WIZARD = 8

# power codes
# Power with smaller number is tested first!

P_SHOT = 101 # everyone has this
P_HARD_JUMP = 102 # everyone has this
P_ZAP = 100 # wands can give this

P_SMITE = 4
P_CLEAVE = 5
P_JAB = 6
P_ALL_OUT_DEFENSE = 7
P_FIGHTING_WITHDRAWAL = 8
P_CHARGE = 9

P_SUPER_CLEAVE = 10 # improved version of P_CLEAVE
P_SUPER_JAB = 11 # improved version of P_JAB
P_SUPER_SMITE = 3.5 # improved version of P_SMITE

P_EASY_JUMP = 50
P_LONG_JUMP = 51 # requires P_EASY_JUMP
P_DODGE = 2
P_PICK_LOCKS = 12 
P_DOUBLE_SHOT = 17
P_TRIPLE_SHOT = 16.5
P_SNEAK = 3

P_BLINK = 16
P_TELEPORTATION = 15
P_FIREBOLT = 13
P_CONFUSION = 18
P_LIGHTNING_BOLT = 19
P_CLAIRVOYANCE = 20
P_WINDBLAST = 18.5

P_EXORCISM = 21
P_HEALING = 22
P_CIRCLE_OF_PROTECTION = 23
P_ADMONISHMENT = 24
P_WALK_THROUGH_FIRE = 25 
P_DETECT_ENEMIES = 1
P_CIRCLE_OF_FIRE = 26

D_TUTORIAL = 0        # done
D_ENTRY = 1           # done  
D_EASY_DUNGEON = 2    # done 
D_MAIN_DUNGEON = 3    # special case
D_CROSSROADS = 4      # done
D_OUTSIDE = 5         # N/A
D_FIREDRAKE = 6       # stub done
D_DROW = 7            # stub done
D_CRYPT = 8           # done one layout, but no final bad guy
D_CAVE = 9            # done one layout
D_MAZE = 10           # done one layout
D_HALL_OF_HEROES = 11 # done
D_HALL_OF_CHAMPIONS = 12 # done
D_TREASURE_ROOM = 13  # done
D_QUIET_DUNGEON = 14  # done one layout
D_GOBLIN_CAVE = 15    # done one layout, but no final bad guy
D_FIERY_PITS = 16     # done one layout
D_TREASURE_ROOM_2 = 17  # done
D_TBC = 99

RM_ENTRY_1 = 1
RM_ENTRY_2 = 2
RM_ENTRY_3 = 3
RM_TUTORIAL_1 = 11
RM_TUTORIAL_2 = 12
RM_TUTORIAL_3 = 13
RM_TUTORIAL_4 = 14
RM_TUTORIAL_5 = 15
RM_CROSSROADS = 20
RM_HEROES_1 = 30
RM_HEROES_2 = 31
RM_CHAMPIONS_1 = 40
RM_CHAMPIONS_2 = 41
RM_DROW_1 = 50
RM_DROW_2 = 51
RM_DROW_3 = 52
RM_FIREDRAKE_1 = 60
RM_FIREDRAKE_2 = 61
RM_FIREDRAKE_3 = 62
RM_TREASURE = 70
RM_TREASURE_2 = 71
RM_STAIRSUP_RIGHT_WITH_RANDOMDOOR_LEFT   = 100
RM_STAIRSUP_LEFT_WITH_RANDOMDOOR_RIGHT   = 101
RM_STAIRSUP_UP_WITH_RANDOMDOOR_DOWN      = 102
RM_STAIRSUP_DOWN_WITH_RANDOMDOOR_UP      = 103
RM_STAIRSDOWN_RIGHT_WITH_RANDOMDOOR_LEFT = 104
RM_STAIRSDOWN_LEFT_WITH_RANDOMDOOR_RIGHT = 105
RM_STAIRSDOWN_UP_WITH_RANDOMDOOR_DOWN    = 106
RM_STAIRSDOWN_DOWN_WITH_RANDOMDOOR_UP    = 107
RM_STAIRSUP_RIGHT_WITH_GOLDDOOR_LEFT     = 110
RM_STAIRSUP_LEFT_WITH_GOLDDOOR_RIGHT     = 111
RM_STAIRSUP_UP_WITH_GOLDDOOR_DOWN        = 112
RM_STAIRSUP_DOWN_WITH_GOLDDOOR_UP        = 113
RM_STAIRSDOWN_RIGHT_WITH_GOLDDOOR_LEFT   = 114
RM_STAIRSDOWN_LEFT_WITH_GOLDDOOR_RIGHT   = 115
RM_STAIRSDOWN_UP_WITH_GOLDDOOR_DOWN      = 116
RM_STAIRSDOWN_DOWN_WITH_GOLDDOOR_UP      = 117
RM_NORMALDOOR_LEFT_RANDOMDOOR_RIGHT      = 118
RM_NORMALDOOR_RIGHT_RANDOMDOOR_LEFT      = 119
RM_NEED_GOLDKEY_TO_EXIT                  = 130
RM_RIVER_SW_NE_V1                        = 140 # no easy crossing
RM_RIVER_SW_N                            = 141 # should allow crossing
RM_RIVER_S_NW_NE                         = 142 # should allow crossings in both directions
RM_RIVER_NW_SE                           = 143 # no easy crossing
RM_RIVER_SW_NE_V2                        = 144 # no easy crossing
RM_TWO_EXITS_AND_DOOR_RIGHT              = 150
RM_TWO_EXITS_AND_DOOR_LEFT               = 151
RM_LOCKED_DOORS_W_E_S_STAIRSUP_N         = 160
RM_GUARANTEED_TREASURE_DOOR_RIGHT        = 170

def opposite(dir):
    return 10-dir

DIR_CHANGE_DOWN = [0,1,1,1,0,0,0,-1,-1,-1] # indexed by a direction code
DIR_CHANGE_RIGHT = [0,-1,0,1,-1,0,1,-1,0,1] # indexed by a direction code

def one_to_x(x):
    return range(1,x+1)

def numkey_to_num(key):
    if key==K_1:
        return 1
    elif key==K_2:
        return 2
    elif key==K_3:
        return 3
    elif key==K_4:
        return 4
    elif key==K_5:
        return 5
    elif key==K_6:
        return 6
    elif key==K_7:
        return 7
    elif key==K_8:
        return 8
    elif key==K_9:
        return 9
    else:
        return 0
    
dir_keys_to_dir = {K_UP:DIR_UP, K_DOWN:DIR_DOWN, K_RIGHT:DIR_RIGHT, K_LEFT:DIR_LEFT, K_KP1:DIR_SW, K_KP2:DIR_DOWN, K_KP3:DIR_SE, K_KP4:DIR_LEFT, K_KP5:DIR_HERE, K_KP6:DIR_RIGHT, K_KP7:DIR_NW, K_KP8:DIR_UP, K_KP9:DIR_NE, K_PERIOD:DIR_HERE, K_h:DIR_DOWN, K_j:DIR_UP, K_k:DIR_LEFT, K_l:DIR_RIGHT, K_y:DIR_NW, K_u:DIR_NE, K_b:DIR_SW, K_n:DIR_SE}
dir_to_dir_key = {DIR_SW:K_KP1, DIR_DOWN:K_KP2, DIR_SE:K_KP3, DIR_LEFT:K_KP4, DIR_HERE:K_KP5, DIR_RIGHT:K_KP6, DIR_NW:K_KP7, DIR_UP:K_KP8, DIR_NE:K_KP9}

def clockwise(dir):
    return [None,DIR_LEFT,DIR_SW,DIR_DOWN,DIR_NW,None,DIR_SE,DIR_UP,DIR_NE,DIR_RIGHT][dir]

def anticlockwise(dir):
    return [None,DIR_DOWN,DIR_SE,DIR_RIGHT,DIR_SW,None,DIR_NE,DIR_LEFT,DIR_NW,DIR_UP][dir]

def permute(pool):
    # Randomly permute whatever list is passed in as pool
    oldlist = []+list(pool)
    newlist = []
    for i in range(len(oldlist)): # = range(26)
        randitem = random.choice(oldlist)
        oldlist.remove(randitem)
        newlist.append(randitem)
    return newlist

def random_positive_int_around(mean,cv):
    return max(0,floor(0.5+random.normalvariate(mean,mean*cv)))
    
def make_shells(max_number):
  shells = {} # key is radius, result is [Pos]
  for number in range(1,max_number+1):
      result = []
      down = -number
      right = -number
      for i in range(2*number):
        down = down + 1
        result.append([down,right])
      for i in range(2*number):
        right = right + 1
        result.append([down,right])
      for i in range(2*number):
        down = down - 1
        result.append([down,right])
      for i in range(2*number):
        right = right - 1
        result.append([down,right])
      shells[number] = result
  return shells

def sentencecase(string):
    return string[0].upper() + string[1:]

lowercase_letters = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']

def make_nice_list(x):
    message = ""
    if len(x)==0:
        return message
    if len(x)>1:
        for name in x[:len(x)-2]:
            message = message + name + ", "
        message = message + x[len(x)-2]
        message = message + " and "
    message = message + x[len(x)-1]
    return message
    
def wait(ms): 
    pygame.time.wait(ms)
    # pass

def text_block_to_list_of_strings(text_block):
    # And remove leading and trailing carriage returns.
    text_block = text_block.strip('\n')+'\n'
    row_length = 0
    for i in text_block:
        row_length = row_length + 1
        if i=='\n':
            break
    column_height = len(text_block)/row_length
    result = []
    for i in range(column_height):
        result.append(text_block[i*row_length:i*row_length+row_length-1])
    return result